home *** CD-ROM | disk | FTP | other *** search
/ CICA 1995 August / CICA - The Ultimate Collection of Shareware for Windows (Disc 2) (August 1995).iso / disc2 / nt / source.exe / POSIX / ELVIS / TIO.C < prev    next >
C/C++ Source or Header  |  1993-07-06  |  17KB  |  864 lines

  1. /* tio.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains terminal I/O functions */
  12.  
  13. #include "config.h"
  14. #if BSD || COHERENT
  15. # include <setjmp.h>
  16. #endif
  17. #include <signal.h>
  18. #include "vi.h"
  19. //#include "curses.h"
  20.  
  21. /* This function reads in a line from the terminal. */
  22. int vgets(prompt, buf, bsize)
  23.     char    prompt;    /* the prompt character, or '\0' for none */
  24.     char    *buf;    /* buffer into which the string is read */
  25.     int    bsize;    /* size of the buffer */
  26. {
  27.     int    len;    /* how much we've read so far */
  28.     int    ch;    /* a character from the user */
  29.     int    quoted;    /* is the next char quoted? */
  30.     int    tab;    /* column position of cursor */
  31.     char    widths[132];    /* widths of characters */
  32. #ifndef NO_DIGRAPH
  33.     int    erased;    /* 0, or first char of a digraph */
  34. #endif
  35.  
  36.     /* show the prompt */
  37.     move(LINES - 1, 0);
  38.     tab = 0;
  39.     if (prompt)
  40.     {
  41.         addch(prompt);
  42.         tab = 1;
  43.     }
  44.     clrtoeol();
  45.     refresh();
  46.  
  47.     /* read in the line */
  48. #ifndef NO_DIGRAPH
  49.     erased =
  50. #endif
  51.     quoted = len = 0;
  52.     for (;;)
  53.     {
  54.         ch = getkey(quoted ? 0 : WHEN_EX);
  55.  
  56.         /* some special conversions */
  57.         if (ch == ctrl('D') && len == 0)
  58.             ch = ctrl('[');
  59. #ifndef NO_DIGRAPH
  60.         if (*o_digraph && erased != 0 && ch != '\b')
  61.         {
  62.             ch = digraph(erased, ch);
  63.             erased = 0;
  64.         }
  65. #endif
  66.  
  67.         /* inhibit detection of special chars (except ^J) after a ^V */
  68.         if (quoted && ch != '\n')
  69.         {
  70.             ch |= 256;
  71.         }
  72.  
  73.         /* process the character */
  74.         switch(ch)
  75.         {
  76.           case ctrl('V'):
  77.             qaddch('^');
  78.             qaddch('\b');
  79.             quoted = TRUE;
  80.             break;
  81.  
  82.           case ctrl('['):
  83.             return -1;
  84.  
  85.           case '\n':
  86. #if OSK
  87.           case '\l':
  88. #else
  89.           case '\r':
  90. #endif
  91.             clrtoeol();
  92.             goto BreakBreak;
  93.  
  94.           case '\b':
  95.             if (len > 0)
  96.             {
  97.                 len--;
  98. #ifndef NO_DIGRAPH
  99.                 erased = buf[len];
  100. #endif
  101.                 for (ch = widths[len]; ch > 0; ch--)
  102.                     addch('\b');
  103.                 if (mode == MODE_EX)
  104.                 {
  105.                     clrtoeol();
  106.                 }
  107.                 tab -= widths[len];
  108.             }
  109.             else
  110.             {
  111.                 return -1;
  112.             }
  113.             break;
  114.  
  115.           default:
  116.             /* strip off quotation bit */
  117.             if (ch & 256)
  118.             {
  119.                 ch &= ~256;
  120.                 quoted = FALSE;
  121.                 qaddch(' ');
  122.                 qaddch('\b');
  123.             }
  124.             /* add & echo the char */
  125.             if (len < bsize - 1)
  126.             {
  127.                 if (ch == '\t')
  128.                 {
  129.                     widths[len] = *o_tabstop - (tab % *o_tabstop);
  130.                     addstr("        " + 8 - widths[len]);
  131.                     tab += widths[len];
  132.                 }
  133.                 else if (ch > 0 && ch < ' ') /* > 0 by GB */
  134.                 {
  135.                     addch('^');
  136.                     addch(ch + '@');
  137.                     widths[len] = 2;
  138.                     tab += 2;
  139.                 }
  140.                 else if (ch == '\177')
  141.                 {
  142.                     addch('^');
  143.                     addch('?');
  144.                     widths[len] = 2;
  145.                     tab += 2;
  146.                 }
  147.                 else
  148.                 {
  149.                     addch(ch);
  150.                     widths[len] = 1;
  151.                     tab++;
  152.                 }
  153.                 buf[len++] = ch;
  154.             }
  155.             else
  156.             {
  157.                 beep();
  158.             }
  159.         }
  160.     }
  161. BreakBreak:
  162.     refresh();
  163.     buf[len] = '\0';
  164.     return len;
  165. }
  166.  
  167.  
  168. /* ring the terminal's bell */
  169. void beep()
  170. {
  171.     if (*o_vbell)
  172.     {
  173.         do_VB();
  174.         refresh();
  175.     }
  176.     else if (*o_errorbells)
  177.     {
  178.         ttywrite("\007", 1);
  179.     }
  180. }
  181.  
  182. static int    manymsgs; /* This variable keeps msgs from overwriting each other */
  183. static char    pmsg[80]; /* previous message (waiting to be displayed) */
  184.  
  185.  
  186. static int showmsg()
  187. {
  188.     /* if there is no message to show, then don't */
  189.     if (!manymsgs)
  190.         return FALSE;
  191.  
  192.     /* display the message */
  193.     move(LINES - 1, 0);
  194.     if (*pmsg)
  195.     {
  196.         standout();
  197.         qaddch(' ');
  198.         qaddstr(pmsg);
  199.         qaddch(' ');
  200.         standend();
  201.     }
  202.     clrtoeol();
  203.  
  204.     manymsgs = FALSE;
  205.     return TRUE;
  206. }
  207.  
  208.  
  209. void endmsgs()
  210. {
  211.     if (manymsgs)
  212.     {
  213.         showmsg();
  214.         addch('\n');
  215.     }
  216. }
  217.  
  218. /* Write a message in an appropriate way.  This should really be a varargs
  219.  * function, but there is no such thing as vwprintw.  Hack!!!
  220.  *
  221.  * In MODE_EX or MODE_COLON, the message is written immediately, with a
  222.  * newline at the end.
  223.  *
  224.  * In MODE_VI, the message is stored in a character buffer.  It is not
  225.  * displayed until getkey() is called.  msg() will call getkey() itself,
  226.  * if necessary, to prevent messages from being lost.
  227.  *
  228.  * msg("")        - clears the message line
  229.  * msg("%s %d", ...)    - does a printf onto the message line
  230.  */
  231. /*VARARGS1*/
  232. void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
  233.     char    *fmt;
  234.     long    arg1, arg2, arg3, arg4, arg5, arg6, arg7;
  235. {
  236.     if (mode != MODE_VI)
  237.     {
  238.         sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
  239.         qaddstr(pmsg);
  240.         addch('\n');
  241.         exrefresh();
  242.     }
  243.     else
  244.     {
  245.         /* wait for keypress between consecutive msgs */
  246.         if (manymsgs)
  247.         {
  248.             getkey(WHEN_MSG);
  249.         }
  250.  
  251.         /* real message */
  252.         sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
  253.         manymsgs = TRUE;
  254.     }
  255. }
  256.  
  257.  
  258. /* This function calls refresh() if the option exrefresh is set */
  259. void exrefresh()
  260. {
  261.     char    *scan;
  262.  
  263.     /* If this ex command wrote ANYTHING set exwrote so vi's  :  command
  264.      * can tell that it must wait for a user keystroke before redrawing.
  265.      */
  266.     for (scan=kbuf; scan<stdscr; scan++)
  267.         if (*scan == '\n')
  268.             exwrote = TRUE;
  269.  
  270. #if MICROSOFT            /* avoid compiler bug */
  271.     scan = stdscr;
  272. #define    stdscr    scan
  273. #endif
  274.     /* now we do the refresh thing */
  275.     if (*o_exrefresh)
  276.     {
  277.         refresh();
  278.     }
  279.     else
  280.     {
  281.         wqrefresh(stdscr);
  282.     }
  283. #if MICROSOFT
  284. #undef    stdscr
  285.     stdscr = scan;
  286. #endif
  287.     if (mode != MODE_VI)
  288.     {
  289.         manymsgs = FALSE;
  290.     }
  291. }
  292.  
  293.  
  294.  
  295. /* These are used for typeahead, and also for fudging the visual @ command */
  296. static char    keybuf[100];    /* array of already-read keys */
  297. static int    nkeys;        /* total number of keys in keybuf */
  298. static int    next;        /* index of next key to return */
  299. #ifndef NO_AT
  300. static int    atnext;        /* index of next key for "@", or 0 normally */
  301. int fromcutbuf(cbname)
  302.     int    cbname;
  303. {
  304.     int    len;
  305.  
  306.     /* fail if we're already doing an @ macro */
  307.     if (atnext > 0 && keybuf[atnext])
  308.     {
  309.         msg("Can't nest @ commands");
  310.         return FALSE;
  311.     }
  312.  
  313.     /* use the empty portion of keybuf[] to get chars from the cut buffer */
  314.     len = cb2str(cbname, keybuf + nkeys, sizeof keybuf - nkeys);
  315.     if (len < 0)
  316.     {
  317.         msg("Invalid cut buffer name.  Must be a-z");
  318.         return FALSE;
  319.     }
  320.     if (len == 0)
  321.     {
  322.         msg("Cut buffer \"%c is empty", cbname);
  323.         return FALSE;
  324.     }
  325.     else if (len >= sizeof keybuf - nkeys)
  326.     {
  327.         msg("Cut buffer \"%c is too large to execute", cbname);
  328.         return FALSE;
  329.     }
  330.  
  331.     /* prepare to "read" those keys on subsequent getkey() calls */
  332.     atnext = nkeys;
  333.     return TRUE;
  334. }
  335. #endif
  336.  
  337. /* This array describes mapped key sequences */
  338. static struct _keymap
  339. {
  340.     char    *name;        /* name of the key, or NULL */
  341.     char    rawin[LONGKEY];    /* the unmapped version of input */
  342.     char    cooked[80];    /* the mapped version of input */
  343.     int    len;        /* length of the unmapped version */
  344.     int    when;        /* when is this key mapped? */
  345. }
  346.     mapped[MAXMAPS];
  347.  
  348. #if !MSDOS && !TOS
  349. # if BSD || COHERENT
  350. static jmp_buf env_timeout;
  351. static int dummy()
  352. {
  353.     longjmp(env_timeout, 1);
  354.     return 0;
  355. }
  356. # else 
  357. static int dummy()
  358. {
  359. }
  360. # endif
  361. #endif
  362.  
  363. /* This function reads in a keystroke for VI mode.  It automatically handles
  364.  * key mapping.
  365.  */
  366. int getkey(when)
  367.     int        when;        /* which bits must be ON? */
  368. {
  369.     static char    *cooked;    /* rawin, or pointer to converted key */ 
  370.     static int    oldwhen;    /* "when" from last time */
  371.     static int    oldleft;
  372.     static long    oldtop;
  373.     static long    oldnlines;
  374.     static char    *cshape;    /* current cursor shape */
  375.     REG char    *kptr;        /* &keybuf[next] */
  376.     REG struct _keymap *km;    /* used to count through keymap */
  377.     REG int        i, j, k;
  378.  
  379. #ifdef DEBUG
  380.     watch();
  381. #endif
  382.  
  383.     /* if this key is needed for delay between multiple error messages,
  384.      * then reset the manymsgs flag and abort any mapped key sequence.
  385.      */
  386.     if (showmsg())
  387.     {
  388.         if (when == WHEN_MSG)
  389.         {
  390.             qaddstr("[More...]");
  391.             refresh();
  392.             cooked = (char *)0;
  393.         }
  394.         else if (when == WHEN_VIINP || when == WHEN_VIREP)
  395.         {
  396.             redraw(cursor, TRUE);
  397.         }
  398.     }
  399.  
  400. #ifndef NO_AT
  401.     /* if we're in the middle of a visual @ macro, take atnext */
  402.     if (atnext > 0)
  403.     {
  404.         if (keybuf[atnext])
  405.         {
  406.             return keybuf[atnext++];
  407.         }
  408.         atnext = 0;
  409.     }
  410. #endif
  411.  
  412.     /* if we're doing a mapped key, get the next char */
  413.     if (cooked && *cooked)
  414.     {
  415.         return *cooked++;
  416.     }
  417.  
  418.     /* if keybuf is empty, fill it */
  419.     if (next == nkeys)
  420.     {
  421. #ifndef NO_CURSORSHAPE
  422.         /* make sure the cursor is the right shape */
  423.         if (has_CQ)
  424.         {
  425.             cooked = cshape;
  426.             switch (when)
  427.             {
  428.               case WHEN_EX:        cooked = CX;    break;
  429.               case WHEN_VICMD:    cooked = CV;    break;
  430.               case WHEN_VIINP:    cooked = CI;    break;
  431.               case WHEN_VIREP:    cooked = CR;    break;
  432.             }
  433.             if (cooked != cshape)
  434.             {
  435.                 cshape = cooked;
  436.                 switch (when)
  437.                 {
  438.                   case WHEN_EX:        do_CX();    break;
  439.                   case WHEN_VICMD:    do_CV();    break;
  440.                   case WHEN_VIINP:    do_CI();    break;
  441.                   case WHEN_VIREP:    do_CR();    break;
  442.                 }
  443.             }
  444.             cooked = (char *)0;
  445.         }
  446. #endif
  447.  
  448. #ifndef NO_SHOWMODE
  449.         /* if "showmode" then say which mode we're in */
  450.         if (*o_smd
  451.          && mode == MODE_VI
  452.          && (when != oldwhen || topline != oldtop || leftcol != oldleft || nlines != oldnlines))
  453.         {
  454.             oldwhen = when;
  455.             oldtop = topline;
  456.             oldleft = leftcol;
  457.             oldnlines = nlines;
  458.  
  459.             if (when & WHEN_VICMD)
  460.             {
  461.                 redraw(cursor, FALSE);
  462.                 move(LINES - 1, COLS - 10);
  463.                 standout();
  464.                 addstr("Command");
  465.                 standend();
  466.                 redraw(cursor, FALSE);
  467.             }
  468.             else if (when & WHEN_VIINP)
  469.             {
  470.                 redraw(cursor, TRUE);
  471.                 move(LINES - 1, COLS - 10);
  472.                 standout();
  473.                 addstr(" Input ");
  474.                 standend();
  475.                 redraw(cursor, TRUE);
  476.             }
  477.             else if (when & WHEN_VIREP)
  478.             {
  479.                 redraw(cursor, TRUE);
  480.                 move(LINES - 1, COLS - 10);
  481.                 standout();
  482.                 addstr("Replace");
  483.                 standend();
  484.                 redraw(cursor, TRUE);
  485.             }
  486.         }
  487.         else
  488. #endif
  489.  
  490.         /* redraw if getting a VI command */
  491.         if (when & WHEN_VICMD)
  492.         {
  493.             redraw(cursor, FALSE);
  494.         }
  495.         /* read the rawin keystrokes */
  496.         refresh();
  497.         while ((nkeys = ttyread(keybuf, sizeof keybuf)) < 0)
  498.         {
  499.             /* terminal was probably resized */
  500.             *o_lines = LINES;
  501.             *o_columns = COLS;
  502.             if (when & (WHEN_VICMD|WHEN_VIINP|WHEN_VIREP))
  503.             {
  504.                 redraw(MARK_UNSET, FALSE);
  505.                 redraw(cursor, (when & WHEN_VICMD) == 0);
  506.                 refresh();
  507.             }
  508.         }
  509.         next = 0;
  510.  
  511.         /* if nkeys == 0 then we've reached EOF of an ex script. */
  512.         if (nkeys == 0)
  513.         {
  514.             tmpabort(TRUE);
  515.             move(LINES - 1, 0);
  516.             clrtoeol();
  517.             refresh();
  518.             endwin();
  519.             exit(1);
  520.         }
  521.     }
  522.  
  523.     /* see how many mapped keys this might be */
  524.     kptr = &keybuf[next];
  525.     for (i = j = 0, k = -1, km = mapped; i < MAXMAPS; i++, km++)
  526.     {
  527.         if ((km->when & when) && km->len > 0 && *km->rawin == *kptr)
  528.         {
  529.             if (km->len > nkeys - next)
  530.             {
  531.                 if (!strncmp(km->rawin, kptr, nkeys - next))
  532.                 {
  533.                     j++;
  534.                 }
  535.             }
  536.             else
  537.             {
  538.                 if (!strncmp(km->rawin, kptr, km->len))
  539.                 {
  540.                     j++;
  541.                     k = i;
  542.                 }
  543.             }
  544.         }
  545.     }
  546.  
  547.     /* if more than one, try to read some more */
  548.     while (j > 1)
  549.     {
  550. #if BSD || COHERENT
  551.         if (setjmp(env_timeout))
  552.         {
  553.             /* we timed out - assume no mapping */
  554.             j = 0;
  555.             break;
  556.         }
  557. #endif
  558. #if ANY_UNIX || DF_POSIX
  559.         signal(SIGALRM, dummy);
  560. #endif
  561. #if OSK
  562.         signal(SIGQUIT, dummy);
  563. #endif
  564.         alarm((unsigned)*o_keytime);
  565.         i = nkeys;
  566.         if ((k = ttyread(keybuf + nkeys, sizeof keybuf - nkeys)) >= 0)
  567.         {
  568.             nkeys += k;
  569.         }
  570.         alarm(0);
  571. #if OSK
  572. # ifndef DEBUG
  573.         signal(SIGQUIT, SIG_IGN);
  574. # endif
  575. #endif
  576.  
  577.         /* if we couldn't read any more, pretend 0 mapped keys */
  578.         if (i == nkeys)
  579.         {
  580.             j = 0;
  581.         }
  582.         else /* else we got some more - try again */
  583.         {
  584.             for (i = j = 0, k = -1, km = mapped; i < MAXMAPS; i++, km++)
  585.             {
  586.                 if ((km->when & when) && km->len > 0 && *km->rawin == *kptr)
  587.                 {
  588.                     if (km->len > nkeys - next)
  589.                     {
  590.                         if (!strncmp(km->rawin, kptr, nkeys - next))
  591.                         {
  592.                             j++;
  593.                         }
  594.                     }
  595.                     else
  596.                     {
  597.                         if (!strncmp(km->rawin, kptr, km->len))
  598.                         {
  599.                             j++;
  600.                             k = i;
  601.                         }
  602.                     }
  603.                 }
  604.             }
  605.         }
  606.     }
  607.  
  608.     /* if unambiguously mapped key, use it! */
  609.     if (j == 1 && k >= 0)
  610.     {
  611.         next += mapped[k].len;
  612.         cooked = mapped[k].cooked;
  613. #ifndef NO_EXTENSIONS
  614.         if ((when & (WHEN_VIINP|WHEN_VIREP))
  615.          && (mapped[k].when & WHEN_INMV))
  616.         {
  617.             return 0; /* special case, means "a movement char follows" */
  618.         }
  619.         else
  620. #endif
  621.         {
  622.             return *cooked++;
  623.         }
  624.     }
  625.     else
  626.     /* assume key is unmapped, but still translate weird erase key to '\b' */
  627.     if (keybuf[next] == ERASEKEY && when != 0)
  628.     {
  629.         next++;
  630.         return '\b';
  631.     }
  632.     else if (keybuf[next] == '\0')
  633.     {
  634.         next++;
  635.         return ('A' & 0x1f);
  636.     }
  637.     else
  638.     {
  639.         return keybuf[next++];
  640.     }
  641. }
  642.  
  643.  
  644. /* This function maps or unmaps a key */
  645. void mapkey(rawin, cooked, when, name)
  646.     char    *rawin;    /* the input key sequence, before mapping */
  647.     char    *cooked;/* after mapping */
  648.     short    when;    /* bitmap of when mapping should happen */
  649.     char    *name;    /* name of the key, if any */
  650. {
  651.     int    i, j;
  652.  
  653. #ifndef NO_EXTENSIONS
  654.     /* if the mapped version starts with the word "visual" then set WHEN_INMV */
  655.     if (!strncmp(cooked, "visual ", 7))
  656.     {
  657.         when |= WHEN_INMV;
  658.         cooked += 7;
  659.     }
  660.     /* if WHEN_INMV is set, then WHEN_VIINP and WHEN_VIREP must be set */
  661.     if (when & WHEN_INMV)
  662.     {
  663.         when |= (WHEN_VIINP | WHEN_VIREP);
  664.     }
  665. #endif
  666.  
  667.     /* see if the key sequence was mapped before */
  668.     j = strlen(rawin);
  669.     for (i = 0; i < MAXMAPS; i++)
  670.     {
  671.         if (mapped[i].len == j
  672.          && !strncmp(mapped[i].rawin, rawin, j)
  673.          && (mapped[i].when & when))
  674.         {
  675.             break;
  676.         }
  677.     }
  678.  
  679.     /* if not already mapped, then try to find a new slot to use */
  680.     if (i == MAXMAPS)
  681.     {
  682.         for (i = 0; i < MAXMAPS && mapped[i].len > 0; i++)
  683.         {
  684.         }
  685.     }
  686.  
  687.     /* no room for the new key? */
  688.     if (i == MAXMAPS)
  689.     {
  690.         msg("No room left in the key map table");
  691.         return;
  692.     }
  693.  
  694.     /* map the key */
  695.     if (cooked && *cooked)
  696.     {
  697.         /* Map the key */
  698.         mapped[i].len = j;
  699.         strncpy(mapped[i].rawin, rawin, j);
  700.         strcpy(mapped[i].cooked, cooked);
  701.         mapped[i].when = when;
  702.         mapped[i].name = name;
  703.     }
  704.     else /* unmap the key */
  705.     {
  706.         mapped[i].len = 0;
  707.     }
  708. }
  709.  
  710. /* Dump keys of a given type - WHEN_VICMD dumps the ":map" keys, and
  711.  * WHEN_VIINP|WHEN_VIREP dumps the ":map!" keys
  712.  */
  713. void dumpkey(when)
  714.     int    when;    /* WHEN_XXXX of mappings to be dumped */
  715. {
  716.     int    i, len, mlen;
  717.     char    *scan;
  718.     char    *mraw;
  719.  
  720.     for (i = 0; i < MAXMAPS; i++)
  721.     {
  722.         /* skip unused entries, or entries that don't match "when" */
  723.         if (mapped[i].len <= 0 || !(mapped[i].when & when))
  724.         {
  725.             continue;
  726.         }
  727.  
  728.         /* dump the key label, if any */
  729.         len = 8;
  730.         if (mapped[i].name)
  731.         {
  732.             qaddstr(mapped[i].name);
  733.             len -= strlen(mapped[i].name);
  734.         }
  735.         do
  736.         {
  737.             qaddch(' ');
  738.         } while (len-- > 0);
  739.  
  740.         /* dump the raw version */
  741.         len = 0;
  742.         mlen = mapped[i].len;
  743.         mraw = mapped[i].rawin;
  744.         for (scan = mraw; scan < mraw + mlen; scan++)
  745.         {
  746.             if (UCHAR(*scan) < ' ' || *scan == '\177')
  747.             {
  748.                 qaddch('^');
  749.                 qaddch(*scan ^ '@');
  750.                 len += 2;
  751.             }
  752.             else
  753.             {
  754.                 qaddch(*scan);
  755.                 len++;
  756.             }
  757.         }
  758.         do
  759.         {
  760.             qaddch(' ');
  761.         } while (++len < 8);
  762.  
  763.         /* dump the mapped version */
  764. #ifndef NO_EXTENSIONS
  765.         if ((mapped[i].when & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP)))
  766.         {
  767.             qaddstr("visual ");
  768.         }
  769. #endif
  770.         for (scan = mapped[i].cooked; *scan; scan++)
  771.         {
  772.             if (UCHAR(*scan) < ' ' || *scan == '\177')
  773.             {
  774.                 qaddch('^');
  775.                 qaddch(*scan ^ '@');
  776.             }
  777.             else
  778.             {
  779.                 qaddch(*scan);
  780.             }
  781.         }
  782.  
  783.         addch('\n');
  784.         exrefresh();
  785.     }
  786. }
  787.  
  788.  
  789.  
  790. #ifndef MKEXRC
  791. /* This function saves the current configuration of mapped keys to a file */
  792. void savekeys(fd)
  793.     int    fd;    /* file descriptor to save them to */
  794. {
  795.     int    i;
  796.     char    buf[80];
  797.  
  798.     /* now write a map command for each key other than the arrows */
  799.     for (i = 0; i < MAXMAPS; i++)
  800.     {
  801.         /* ignore keys that came from termcap */
  802.         if (mapped[i].name)
  803.         {
  804.             continue;
  805.         }
  806.  
  807.         /* If this isn't used, ignore it */
  808.         if (mapped[i].len <= 0)
  809.         {
  810.             continue;
  811.         }
  812.  
  813.         /* write the map command */
  814. #ifndef NO_EXTENSIONS
  815.         if (mapped[i].when & WHEN_INMV)
  816.         {
  817. #if OSK
  818.             char    fmt[80];
  819.             sprintf(fmt, "map%%s %%.%ds %%s\n", mapped[i].len);
  820.             sprintf(buf, fmt,
  821.                 (mapped[i].when & WHEN_VICMD) ? "" : "!",
  822. #else
  823.             sprintf(buf, "map%s %.*s visual %s\n",
  824.                 (mapped[i].when & WHEN_VICMD) ? "" : "!",
  825.                 mapped[i].len,
  826. #endif
  827.                 mapped[i].rawin,
  828.                 mapped[i].cooked);
  829.             twrite(fd, buf, strlen(buf));
  830.         }
  831.         else
  832. #endif
  833.         {
  834.             if (mapped[i].when & WHEN_VICMD)
  835.             {
  836. #if OSK
  837.                 char    fmt[80];
  838.                 sprintf(fmt, "map %%.%ds %%s\n", mapped[i].len);
  839.                 sprintf(buf, fmt,
  840. #else
  841.                 sprintf(buf, "map %.*s %s\n", mapped[i].len,
  842. #endif
  843.                     mapped[i].rawin,
  844.                     mapped[i].cooked);
  845.                 twrite(fd, buf, strlen(buf));
  846.             }
  847.             if (mapped[i].when & (WHEN_VIINP | WHEN_VIREP))
  848.             {
  849. #if OSK
  850.                 char    fmt[80];
  851.                 sprintf(fmt, "map! %%.%ds %%s\n", mapped[i].len);
  852.                 sprintf(buf, fmt,
  853. #else
  854.                 sprintf(buf, "map! %.*s %s\n", mapped[i].len,
  855. #endif
  856.                     mapped[i].rawin,
  857.                     mapped[i].cooked);
  858.                 twrite(fd, buf, strlen(buf));
  859.             }
  860.         }
  861.     }
  862. }
  863. #endif
  864.